package com.qs.commontools.common.service;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.qs.commontools.common.exception.WaterMarkException;
import com.qs.commontools.utils.base.StringUtils;
import com.qs.commontools.utils.file.QRcodeTool;
import com.qs.commontools.utils.file.VerificationTool;
import com.qs.commontools.utils.file.WaterMarkTool;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Hashtable;
import java.util.Random;

/**
 * 图片处理层
 * @author qiusuo
 * @since 2021-09-27
 */
public class ImgService {

    private static ImgService instance;

    private ImgService() {
    }

    /**
     * 方法同步，调用效率低
     * @return
     */
    public static synchronized ImgService getInstance(){
        if(instance == null){
            instance = new ImgService();
        }
        return instance;
    }

    /**
     * x 轴扭曲图片
     * @param g
     * @param w1
     * @param h1
     * @param color
     */
    public  void shearX(Graphics g, int w1, int h1, Color color) {
        Random random=new Random();
        int period = 2;

        boolean borderGap = true;
        int frames = 1;
        int phase = random.nextInt(2);
        for (int i = 0; i < h1; i++) {
            double d = (double) (period >> 1)* Math.sin((double) i / (double) period + (2.2831853071795862D * (double) phase)/ (double) frames);
            g.copyArea(0, i, w1, 1, (int) d, 0);
            if (borderGap) {
                g.setColor(color);
                g.drawLine((int) d, i, 0, i);
                g.drawLine((int) d + w1, i, w1, i);
            }
        }
    }

    /**
     * y轴扭曲图片
     * @param g
     * @param w1
     * @param h1
     * @param color
     */
    public  void shearY(Graphics g, int w1, int h1, Color color) {
        Random random=new Random();
        // 50;
        int period = random.nextInt(40) + 10;
        boolean borderGap = true;
        int frames = 20;
        int phase = random.nextInt(2);
        for (int i = 0; i < w1; i++) {
            double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (2.2831853071795862D * (double) phase)/ (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap) {
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                g.drawLine(i, (int) d + h1, i, h1);
            }
        }
    }

    /**
     * inputStream转Byte数组
     * @param inputStream
     * @return
     */
    public  byte[] inputStreamToByte(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        // 创建一个Buffer字符串
        byte[] buffer = new byte[1024];
        // 每次读取的字符串长度，如果为-1，代表全部读取完毕
        int len = 0;
        // 使用一个输入流从buffer里把数据读取出来
        while( (len = inputStream.read(buffer)) != -1 ){
            // 用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
            outStream.write(buffer, 0, len);
        }
        outStream.flush();
        // 关闭输入流
        inputStream.close();
        // 把outStream里的数据写入内存
        // 得到二进制数据，以二进制封装得到数据，具有通用性
        byte[] data = outStream.toByteArray();
        outStream.close();
        return data;
    }

    /**
     * BufferedImage对象转InputStream
     * @param bufferedImage BufferedImage对象
     * @param suffix 后缀
     * @return
     */
    public  InputStream bufferedImageToInputStream(BufferedImage bufferedImage, String suffix) {
        // 结果
        InputStream inputStream = new ByteArrayInputStream(bufferedImageToByte(bufferedImage,suffix));
        return inputStream;
    }

    /**
     * BufferedImage对象转Byte数组
     * @param bufferedImage BufferedImage对象
     * @param suffix 后缀
     * @return
     */
    public  byte[] bufferedImageToByte(BufferedImage bufferedImage, String suffix) {
        // 将bufferedimage 转换成 inputstream
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ImageOutputStream imOut = null;
        try {
            imOut = ImageIO.createImageOutputStream(bs);
            // bufferedimage对象写进out流
            ImageIO.write(bufferedImage, suffix, imOut);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 结果
        return bs.toByteArray();
    }


    /**
     * todo 绘图方法
     * @param entity
     * @return
     */
    public  byte[] draw(VerificationTool entity) {
        Integer width = entity.getWidth();
        Integer height = entity.getHeight();
        // 随机操作对象
        Random r = new Random();
        // 创建画板
        BufferedImage imageBoard = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        // 创建画纸
        Graphics imagePaper = imageBoard.getGraphics();
        // 绘制背景
        // setColor（）方法，可理解为画笔，在绘制任何东西前要选好画笔，即颜色
        // 调用fillRect（）进行轮廓的绘制，后续的绘制范围不会超过这个轮廓
        imagePaper.setColor(entity.getBackgroundColor());
        imagePaper.fillRect(0,0,width,height);
        // 绘制干扰线
        // 检验干扰线条数
        // 设置干扰线宽度
        BasicStroke   stokeLine   =   new   BasicStroke(entity.getInterLineWeight());
        // 转换宽度画笔
        Graphics2D g2D = (Graphics2D) imagePaper;
        g2D.setStroke(stokeLine);
        if (entity.getInterLineNum() > 0) {
            // 干扰线绘制范围
            int x = r.nextInt(4), y = 0;
            int x1 = width - r.nextInt(4), y1 = 0;
            for(int i=0; i < entity.getInterLineNum(); i++){
                // imagePaper.setColor(entity.getInterLineColor())
                g2D.setColor(entity.getInterLineColor());
                y = r.nextInt(height - r.nextInt(4));
                y1 = r.nextInt(height - r.nextInt(4));
                // imagePaper.drawLine(x,y,x1,y1)
                g2D.drawLine(x,y,x1,y1);
            }
        }
        // 写验证码
        // 写验证码时调用drawString（）方法，为了不整整齐齐而且重叠的写，应将每个字符的高度和水平位置随机，重点在于每绘制完一个字符后，需将画笔的水平坐标往右边移动一定的位置，这里我用了依据宽度浮动
        //字体大小为图片高度的80%
        int fsize = (int)(height*0.8);
        int fx = 0;
        int fy = fsize;
        imagePaper.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,fsize));
        //写字符
        for(int i = 0; i < entity.getCode().length(); i++){
            //每个字符高低是否随机
            fy = entity.isRandomLocation() ? (int)((Math.random() * 0.3 + 0.6) * height):fy;
            imagePaper.setColor(entity.getCodeColor());
            imagePaper.drawString(entity.getCode().charAt(i) + "", fx, fy);
            //依据宽度浮动
            fx += (width / entity.getCode().length()) * (Math.random() * 0.3 + 0.8);
        }

        // 扭曲图片
        // 图片的扭曲就是将图片水平和垂直按不同比例平移，copyArea（）方法简单明了，直接是复制区域，也是同个意识
        shearX(imagePaper, width, height, entity.getBackgroundColor());
        shearY(imagePaper, width, height, entity.getBackgroundColor());

        // 添加无规则点点
        // 噪声率
        float yawpRate = entity.getPointRate();
        //噪点数量
        int area = (int) (yawpRate * width * height);
        for (int i = 0; i < area; i++) {
            int xxx = r.nextInt(width);
            int yyy = r.nextInt(height);
            int rgb = entity.getPointColor().getRGB();
            imageBoard.setRGB(xxx, yyy, rgb);
        }
        // 结束绘制
        imagePaper.dispose();


        return bufferedImageToByte(imageBoard, entity.getSuffix());
    }



    /**
     * todo 给图片添加水印文字、可设置水印文字的旋转角度
     *
     * @param entity
     */
    public byte[] waterMark(WaterMarkTool entity) throws IOException, WaterMarkException {
        // 原图片设置
        Image srcImg = null;
                // 获得原始图片路径
        File srcImgFile = entity.getSrcImg();

        if (!srcImgFile.exists()) {
            throw new WaterMarkException("原始图片文件不存在,当前设置的源文件路径:" + srcImgFile.getCanonicalPath());
        } else {
            srcImg = ImageIO.read(srcImgFile);
            if (null == srcImg) {
                throw new FileNotFoundException("需要被添加水印的图片文件不存在,或图片由于更改后缀名导致和文件本身属性不一致");
            }
        }
//        String name = sorceFile.getName();

        // 原图片的宽
        Integer panelWidth = srcImg.getWidth(null);
        // 原图片的长
        Integer panelHeight = srcImg.getHeight(null);

        // 创建画布
        BufferedImage buffImg = new BufferedImage(panelWidth,
                panelHeight, BufferedImage.TYPE_INT_RGB);

        // 得到画笔对象
        Graphics2D g = buffImg.createGraphics();
        RenderingHints rh=new RenderingHints(RenderingHints. KEY_ANTIALIASING,
                RenderingHints. VALUE_ANTIALIAS_ON);
        rh.put(RenderingHints.KEY_STROKE_CONTROL
                , RenderingHints.VALUE_STROKE_PURE);
        rh.put(RenderingHints.KEY_ALPHA_INTERPOLATION
                , RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        // 设置对线段的锯齿状边缘处理
//        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
//                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHints(rh);
        g.drawImage(
                srcImg.getScaledInstance(panelWidth, panelHeight, Image.SCALE_SMOOTH), 0, 0,
                null);
        // 设置水印旋转
        if (null != entity.getAngle()) {
            g.rotate(Math.toRadians(entity.getAngle()),
                    (double) buffImg.getWidth() / 2,
                    (double) buffImg.getHeight() / 2);
        }
        // 设置水印文字颜色
        g.setColor(entity.getColor());
        // 设置水印文字Font
        g.setFont(entity.getFont());
        // 设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                entity.getOpacity()));
        // 第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)

        // 先判断是否需要绘制 图片水印
        if (null == entity.getIcon()) {
            if (!StringUtils.isBlank(entity.getText())) {
                // 绘制文本水印
                drawTextWaterMark(g,entity,panelHeight,panelWidth);
            }

        } else {
            // 判断图片水印中图片是否存在
            if (!entity.getIcon().exists()) {
                throw new WaterMarkException("水印图片不存在：" + entity.getIcon().getCanonicalPath());
            } else {
                Integer iconWidth = entity.getIconWidth() == null ? (panelWidth > 80 ? 80 : panelWidth) : entity.getIconWidth();
                Integer iconHeight = entity.getIconHeight() == null ? (panelHeight > 80 ? 80 : panelHeight) : entity.getIconHeight();
                // 水印图片的路径 水印图片一般为gif或者png的，这样可设置透明度
//                ImageIcon imgIcon = new ImageIcon(entity.getIcon().getCanonicalPath());
                // 得到Image对象
//                Image img = imgIcon.getImage();
                // 根据比率缩小水印图片
                Image img = resize(iconWidth, iconHeight, entity.getIcon());
                // 图片水印的缩略后的长宽
                int iconResWidth = img.getWidth(null);
                int iconResHeight = img.getHeight(null);

                // 如果图片水印的横纵坐标都是空，则绘制多个，否则绘制定位的单个图片水印
                if (entity.getIconPositionX() != null || entity.getIconPositionY() != null) {

                    // 首先绘制文本水印
                    if (!StringUtils.isBlank(entity.getText())) {
                        drawTextWaterMark(g,entity,panelHeight,panelWidth);
                    }

                    // 再绘制图片水印
                    int iconPositionX = entity.getIconPositionX() == null ? panelWidth - iconResWidth - 10 : entity.getIconPositionX();
                    int iconPositionY = entity.getIconPositionY() == null ? 10 : entity.getIconPositionY();

                    // 得到画笔对象
                    Graphics2D g2 = buffImg.createGraphics();
                    if (null != entity.getIconAngle()) {
                        g2.rotate(Math.toRadians(entity.getIconAngle()),
                                (double) buffImg.getWidth() / 2,
                                (double) buffImg.getHeight() / 2);
                    }
                    // 图片水印透明度
                    float opa = entity.getIconOpacity() == null ? 1f : entity.getIconOpacity();
                    // 设置图片水印的透明度
                    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                            opa));
                    g2.drawImage(img, iconPositionX, iconPositionY , null);

                } else {
                    // 文本水印的内容
                    String text = entity.getText();
                    // 文本水印的内容长度
                    int textLen = text.length();
                    // 文本字体的大小
                    int fontSize = entity.getFont().getSize();
                    // 水印水平起始位置
                    int horizontalPosition = entity.getHorizontalPosition();
                    // 水印垂直起始位置
                    int verticalPosition = entity.getVerticalPosition();
                    // 水平水印间隔
                    Integer horInterval = entity.getHorizontalInterval() == null ? 0 : entity.getHorizontalInterval();
                    // 垂直水印间隔
                    Integer verInterval = entity.getVerticalInterval() == null ? 0 : entity.getVerticalInterval();
                    // 垂直数量
                    Integer verNum = entity.getHorizontalNum() == null || entity.getHorizontalNum() == 0 ?
                            panelHeight / (fontSize + iconResHeight + horInterval) + 1 : entity.getHorizontalNum();
                    // 横向数量
                    Integer horNum = entity.getVerticalNum() == null || entity.getVerticalNum() == 0 ?
                            panelWidth / (fontSize + iconResWidth + verInterval) + 1 : entity.getVerticalNum();

                    // 垂直真正间隔,如果字体比图片的高度还大，那么垂直间隔就需要以字体大小为准
                    int verInt = fontSize < iconResHeight ? iconResHeight : fontSize;
                    for (int x = 0; x < verNum; x ++) {
                        for (int y = 0; y < horNum; y ++) {
                            // 该次循环起始X位置
                            int horpo = horizontalPosition + x * (textLen * fontSize + 2 * horInterval + iconResWidth);
                            g.drawString(entity.getText(),
                                    horpo,
                                    verticalPosition + y * (verInt + verInterval));
                            g.drawImage(img,horpo + textLen * fontSize + horInterval,
                                    verticalPosition + y * (verInt + verInterval) - iconResHeight / 2,
                                    null);
                        }
                    }
                }

            }
        }


        // 释放资源
        g.dispose();

        String suffix = srcImgFile.getName().substring(srcImgFile.getName().lastIndexOf(".") + 1);
//        FileOutputStream outputStream = new FileOutputStream("C:\\Users\\hanweb\\Desktop\\8.jpg");;
//        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outputStream);
//        JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buffImg);
//        //设置1 原图保存
//        param.setQuality(1, true);
//        encoder.encode(buffImg, param);
//        outputStream.close();
        return bufferedImageToByte(buffImg,suffix);

    }

    /**
     * 绘制文本水印
     */
    private void drawTextWaterMark(Graphics2D g, WaterMarkTool entity, Integer panelHeight, Integer panelWidth) {
        // 是否只绘制单组文本和图标
        if (entity.getSingle()) {
            // 绘文本水印
            g.drawString(entity.getText(), entity.getHorizontalPosition(), entity.getVerticalPosition());
        } else {
            Integer fontSize = entity.getFont().getSize();
            // 水平水印间隔
            Integer horInterval = entity.getHorizontalInterval() == null ? 0 : entity.getHorizontalInterval();
            // 垂直水印间隔
            Integer verInterval = entity.getVerticalInterval() == null ? 0 : entity.getVerticalInterval();
            // 垂直数量
            Integer verNum = entity.getHorizontalNum() == null || entity.getHorizontalNum() == 0 ?
                    panelHeight / (fontSize + horInterval) + 1 : entity.getHorizontalNum();
            // 横向数量
            Integer horNum = entity.getVerticalNum() == null || entity.getVerticalNum() == 0 ?
                    panelWidth / (fontSize + verInterval) + 1 : entity.getVerticalNum();

            for (int x = 0; x < verNum; x ++) {

                for (int y = 0; y < horNum; y ++) {
                    g.drawString(entity.getText(),
                            entity.getHorizontalPosition() + x * (entity.getText().length() * fontSize + horInterval),
                            entity.getVerticalPosition() + y * (fontSize + verInterval));
                }
            }
        }
    }



    /**
     * 强制按照原比例压缩/放大图片到固定的大小
     * @param width int 新宽度
     * @param height int 新高度
     * @param file 图片文件
     * @throws IOException
     */
    public BufferedImage resize(int width, int height, File file) throws IOException {
        return resize(width, height, file, true);
    }

    /**
     * 压缩/放大图片到固定的大小
     * @param width int 新宽度
     * @param height int 新高度
     * @param file 图片文件
     * @param proportion 是否按照比例
     * @throws IOException
     */
    public BufferedImage resize(int width, int height, File file, boolean proportion) throws IOException {
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在");
        }
        InputStream fileStream = new FileInputStream(file);
        Image srcImage = ImageIO.read(fileStream);
        if (null == srcImage) {
            throw new FileNotFoundException("图片文件不存在,或图片由于更改后缀名导致和文件本身属性不一致");
        }
        Integer imageWidth = srcImage.getWidth(null);
        Integer imageHeight = srcImage.getHeight(null);

        // 是否按照比例放大缩小
        if (proportion) {
            //得到合适的压缩大小，按比例。
            if ( imageWidth >= imageHeight) {
                width = width;
                height = (int)Math.round((imageHeight * width * 1.0 / imageWidth));
            } else {
                height = height;
                width = (int)Math.round((imageWidth * height * 1.0 / imageHeight));
            }

        } else {
            if (imageWidth < width) {
                width = imageWidth;
            }
            if (imageHeight < height) {
                height = imageHeight;
            }
        }

        //构建图片对象
        BufferedImage bufferedImage = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        //绘制缩小后的图
        bufferedImage.getGraphics().drawImage(srcImage, 0, 0, width, height, null);
        return bufferedImage;
    }

    public  BufferedImage resize(File src,int size) throws IOException {
//        try
//        {
//            Image inImage=Toolkit.getDefaultToolkit().createImage(in);
//            ImageIcon inImageIcon = new ImageIcon(in);
//
//            int imh = inImageIcon.getIconHeight();
//            int imw = inImageIcon.getIconWidth();
//            double scale;
//            if( imh <= maxDim && imw <= maxDim ) {
//                scale = 1;
//            } else if( imh > imw ) {
//                scale = (double) maxDim / (double) imh;
//            } else {
//                scale = (double) maxDim / (double) imw;
//            }
//
//            int scaledW = (int) (scale * imw);
//            int scaledH = (int) (scale * imh);
//
//            Image img = inImage.getScaledInstance(scaledW, scaledH, Image.SCALE_FAST);
//            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
//            JimiRasterImage raster = Jimi.createRasterImage(img.getSource());
//            // --java.io.ByteArrayOutputStream
//            Jimi.putImage("image/jpeg", raster, outStream);
//            outStream.flush();
//            outStream.close();
//            return outStream.toByteArray();
//
//        }
//        catch(Exception ex)
//        {
//            ex.printStackTrace();
//            return null;
//        }

//        File srcFile = new File(src);
//        File destFile = new File(dest);

        long fileSize = src.length();
        //文件大于size k时，才进行缩放,注意：size以K为单位
        if(fileSize < size * 1024) {
            return null;
        }

        Double rate = (size * 1024 * 0.5) / fileSize; // 获取长宽缩放比例

        BufferedImage bufImg = ImageIO.read(src);
        Image Itemp = bufImg.getScaledInstance(bufImg.getWidth(), bufImg.getHeight(), Image.SCALE_SMOOTH);

        AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(rate, rate), null);
        Itemp = ato.filter(bufImg, null);
        return (BufferedImage)Itemp;
//        try {
//            ImageIO.write((BufferedImage) Itemp,dest.substring(dest.lastIndexOf(".")+1), destFile);
//        } catch (Exception ex) {
//            ex.printStackTrace();
//        }

    }

    /**
     * todo 创建二维码
     * @return
     */
    public byte[] buildQRcode(QRcodeTool entity) throws WriterException, IOException {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        // 设置纠错等级L/M/Q/H,纠错等级越高越不易识别，当前设置等级为最高等级H
        hints.put(EncodeHintType.ERROR_CORRECTION, entity.getErrorCorrectionLevel());
        // 设置编码字符集utf-8
        hints.put(EncodeHintType.CHARACTER_SET, entity.getCharset());
        // 设置空白区域大小可设置范围为0-10，但仅四个变化0 1(2) 3(4 5 6) 7(8 9 10)
        hints.put(EncodeHintType.MARGIN, entity.getMargin());
        // 生成图片类型为QRCode
        BarcodeFormat format = BarcodeFormat.QR_CODE;
        // 创建位矩阵对象
        BitMatrix bitMatrix = new MultiFormatWriter().encode(entity.getHyperlink(),
                format, entity.getSize(), entity.getSize(), hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                        : 0xFFFFFFFF);
            }
        }

        // 是否要添加logo
        if (null != entity.getLogo()) {
            if (!entity.getLogo().exists()) {
                throw new FileNotFoundException("logo文件不存在");
            } else {
                // 获取logo文件的img对象
                Image logoImg = ImageIO.read(entity.getLogo());
                if (null == logoImg) {
                    throw new FileNotFoundException("图片文件不存在,或图片由于更改后缀名导致和文件本身属性不一致");
                }
                int logoWidth = logoImg.getWidth(null);
                int logoHeight = logoImg.getHeight(null);
                // 压缩LOGO
                if (entity.getNeedCompress()) {
                    if (logoWidth > entity.getWidth()) {
                        logoWidth = entity.getWidth();
                    }
                    if (logoHeight > entity.getHeight()) {
                        logoHeight = entity.getHeight();
                    }
                    Image logoImage = logoImg.getScaledInstance(logoWidth, logoHeight,
                            Image.SCALE_SMOOTH);
                    BufferedImage tag = new BufferedImage(logoWidth, logoHeight,
                            BufferedImage.TYPE_INT_RGB);
                    Graphics g = tag.getGraphics();
                    // 绘制缩小后的图
                    g.drawImage(logoImage, 0, 0, null);
                    g.dispose();
                    logoImg = logoImage;
                }
                // 插入LOGO
                Graphics2D graph = image.createGraphics();
                int x = (entity.getSize() - logoWidth) / 2;
                int y = (entity.getSize() - logoHeight) / 2;
                graph.drawImage(logoImg, x, y, logoWidth, logoHeight, null);
                Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoWidth, 6, 6);
                graph.setStroke(new BasicStroke(3f));
                graph.draw(shape);
                graph.dispose();
            }
        }

        return bufferedImageToByte(image,entity.getSuffix());

    }

    /**
     * 解析二维码
     *
     * @param file
     *            二维码图片
     * @return
     * @throws Exception
     */
    public String decodeQRcode(File file) throws NotFoundException, IOException {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(
                image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }
}
